Méthodologie d'Analyse des Données Quantitatives¶
Introduction :¶
Dans cette étude on va présenter la méthodologie qu'on a utilisé pour analyser les données quantitatives dans un travail d'analyse exploratoire des données (EDA) sur le jeu de données sur les prix immobiliers de Californie. Dans cette analyse, on a utilisé une approche systématique pour découvrir des informations et des schémas au sein de ce jeu de données. on va vous guider à travers chaque étape, en fournissant des exemples et en illustrant le travail à mesure que nous progressons.
from sklearn.datasets import fetch_california_housing
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
sns.set_theme(style = "darkgrid")
import warnings
warnings.filterwarnings("ignore")
import plotly.io as pio
pio.renderers.default = "notebook+pdf"
data = fetch_california_housing(as_frame=True)
data = data.frame
sample_data = data.sample(n=900, random_state=42)
data.head()
| MedInc | HouseAge | AveRooms | AveBedrms | Population | AveOccup | Latitude | Longitude | MedHouseVal | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 8.3252 | 41.0 | 6.984127 | 1.023810 | 322.0 | 2.555556 | 37.88 | -122.23 | 4.526 |
| 1 | 8.3014 | 21.0 | 6.238137 | 0.971880 | 2401.0 | 2.109842 | 37.86 | -122.22 | 3.585 |
| 2 | 7.2574 | 52.0 | 8.288136 | 1.073446 | 496.0 | 2.802260 | 37.85 | -122.24 | 3.521 |
| 3 | 5.6431 | 52.0 | 5.817352 | 1.073059 | 558.0 | 2.547945 | 37.85 | -122.25 | 3.413 |
| 4 | 3.8462 | 52.0 | 6.281853 | 1.081081 | 565.0 | 2.181467 | 37.85 | -122.25 | 3.422 |
sample_data_norm = sample_data.copy(deep=True)
mu = pd.Series({col: 0 for col in sample_data.columns}, dtype="float32")
sigma = pd.Series({col: 0 for col in sample_data.columns}, dtype="float32")
for col in sample_data.columns:
mu[col] = sample_data[col].mean()
sigma[col] = sample_data[col].std()
sample_data_norm[col] = (sample_data[col] - mu[col]) / sigma[col]
Étape 1 : Analyse des Variables Simples¶
import plotly.express as px
import pandas as pd
ddf = data.copy()
ddf["quantile"] = pd.qcut(data["MedHouseVal"],
[0, .25, .5, .75, .9, 1.],
labels=False)
fig = px.scatter_mapbox(ddf,
lat="Latitude",
lon="Longitude",
color="quantile",
#color_continuous_scale=["fuchsia"],
size="MedInc",
zoom=5,
height=800,
width=1080)
fig.update_layout(mapbox_style="open-street-map")
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
image_bytes = fig.to_image(format='png', width=1200, height=700, scale=1)
#instead of using fig.show()
from IPython.display import Image
Image(image_bytes)
Dans la phase initiale de notre analyse, nous avons effectué une analyse des variables simples. Voici ce que nous avons fait :
1.1 Statistiques Sommaires et STatistiques de Normalité :¶
Le calcule des statistiques sommaires telles que la moyenne, la médiane, max, min, et l'écart type. en plus, des statistiques de normalité comme Kurtosis, Skewness pour comprendre la distribution.
from scipy.stats import skew, kurtosis
import pandas_flavor as pf
skimmed_data = data.describe().transpose()
skimmed_data['Skewness'] = data.apply(lambda x: skew(x))
skimmed_data['Kurtosis'] = data.apply(lambda x: kurtosis(x))
from scipy.stats import jarque_bera
skimmed_data['Jarque_Bera'] = data.apply(lambda x: jarque_bera(x)[0])
skimmed_data = skimmed_data.reset_index().rename(columns={'index': 'Variable'})
numeric_cols = skimmed_data.select_dtypes(include=[float]).columns
skimmed_data[numeric_cols] = skimmed_data[numeric_cols].round(3)
skimmed_data
| Variable | count | mean | std | min | 25% | 50% | 75% | max | Skewness | Kurtosis | Jarque_Bera | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | MedInc | 20640.0 | 3.871 | 1.900 | 0.500 | 2.563 | 3.535 | 4.743 | 15.000 | 1.647 | 4.951 | 3.040708e+04 |
| 1 | HouseAge | 20640.0 | 28.639 | 12.586 | 1.000 | 18.000 | 29.000 | 37.000 | 52.000 | 0.060 | -0.801 | 5.639180e+02 |
| 2 | AveRooms | 20640.0 | 5.429 | 2.474 | 0.846 | 4.441 | 5.229 | 6.052 | 141.909 | 20.696 | 879.140 | 6.661564e+08 |
| 3 | AveBedrms | 20640.0 | 1.097 | 0.474 | 0.333 | 1.006 | 1.049 | 1.100 | 34.067 | 31.315 | 1636.315 | 2.306047e+09 |
| 4 | Population | 20640.0 | 1425.477 | 1132.462 | 3.000 | 787.000 | 1166.000 | 1725.000 | 35682.000 | 4.935 | 73.535 | 4.734157e+06 |
| 5 | AveOccup | 20640.0 | 3.071 | 10.386 | 0.692 | 2.430 | 2.818 | 3.282 | 1243.333 | 97.632 | 10648.430 | 9.754739e+10 |
| 6 | Latitude | 20640.0 | 35.632 | 2.136 | 32.540 | 33.930 | 34.260 | 37.710 | 41.950 | 0.466 | -1.118 | 1.821268e+03 |
| 7 | Longitude | 20640.0 | -119.570 | 2.004 | -124.350 | -121.800 | -118.490 | -118.010 | -114.310 | -0.298 | -1.330 | 1.826564e+03 |
| 8 | MedHouseVal | 20640.0 | 2.069 | 1.154 | 0.150 | 1.196 | 1.797 | 2.647 | 5.000 | 0.978 | 0.328 | 3.380475e+03 |
1.2 Boîtes à Moustaches :¶
Les boîtes à moustaches ont été employées pour mettre en évidence les valeurs aberrantes et les variations importantes dans les prix des logements. Elles offrent une vue synthétique des données, mettant en évidence les quartiles et les données extrêmes et offre une visualisation de la table du sommaire statistique.
custom_palette = sns.color_palette("flare", 10)
plt.figure(figsize=(10, 7))
sns.boxplot(data=sample_data_norm, palette=custom_palette)
plt.subplots_adjust(hspace=0.7, wspace=0.4)
plt.show()
1.3 Visualisation des Histogrammes :¶
Visualisation des histogrammes pour représenter graphiquement et comprendre la distribution de chaque variable.
fig, axes = plt.subplots(nrows=3, ncols=3, figsize=(12, 10))
for i, column in enumerate(sample_data.columns):
row, col = divmod(i, 3)
ax = axes[row, col]
sns.distplot(sample_data[column], bins=10, ax=ax, color='blue', kde=True)
ax.set_title(f'Distribution of {column}')
plt.subplots_adjust(hspace=0.7, wspace=0.4)
plt.show()
On a discrétisé en groupes la variable, ce qui nous a permis de regrouper des maisons par tranches d'âge. Ensuite, on a créé un graphique à barres pour illustrer la distribution des maisons dans chaque tranche d'âge.
bin_edges = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
bin_labels = ['0-9', '10-19', '20-29', '30-39', '40-49', '50-59', '60-69', '70-79', '80-89', '90+']
# Create a new column with the age bins
data['age_bins'] = pd.cut(data['HouseAge'], bins=bin_edges, labels=bin_labels)
# Group by the age bins and count the number of houses in each bin
age_grouped = data['age_bins'].value_counts().reset_index()
age_grouped.columns = ['Age Group', 'Count']
# Create a bar plot using Plotly Express
fig = px.bar(age_grouped, x='Age Group', y='Count', title='House Age Distribution')
fig.update_layout(width=800, height=600)
fig.show()
Étape 2 : Analyse Multivariée¶
Dans la deuxième étape, on a exploré les relations entre différentes variables ie analyse bivariée pour identifier les corrélations et les tendances. Voici ce qu'on a fait :
2.1 Calcul de la Corrélation :¶
Le calcul des coefficients de corrélation nous permet de mesurer la force et la direction des relations entre les variables. Une corrélation positive indique une augmentation conjointe, tandis qu'une corrélation négative indique une variation inverse.
data = data.drop("age_bins",axis = 1)
correlation_matrix = data.corr()
plt.figure(figsize=(8, 6))
sns.heatmap(correlation_matrix, annot=True, cmap=sns.cubehelix_palette(as_cmap=True))
plt.title("Correlation Matrix Heatmap");
2.2 Nuages de Points (Scatter Plots) :¶
Les nuages de points sont des graphiques bidimensionnels qui représentent la relation entre deux variables. Ils nous aident à visualiser les tendances, les schémas et les valeurs atypiques dans les données. L'utilisation du "pair plot" permet d'observer les interactions entre différentes variables en un seul graphique.
columns_drop = ["Longitude", "Latitude"]
rng = np.random.RandomState(0)
indices = rng.choice(np.arange(data.shape[0]), size=500, replace=False)
subset = data.iloc[indices].drop(columns=columns_drop)
subset["MedHouseVal"] = pd.qcut(subset["MedHouseVal"], 6, retbins=False)
subset["MedHouseVal"] = subset["MedHouseVal"].apply(lambda x: x.mid)
sns.pairplot(data=subset, hue="MedHouseVal", palette="viridis");
Pretraitement¶
on a appliqué la normalisation aux données d'âge pour mettre toutes les variables sur une échelle comparable.
df = data.copy(deep=True)
μ = pd.Series({col: 0 for col in data.columns}, dtype="float32")
σ = pd.Series({col: 0 for col in data.columns}, dtype="float32")
for col in data.columns:
μ[col] = data[col].mean()
σ[col] = data[col].std()
df[col] = (data[col] - μ[col]) / σ[col]
df.head()
| MedInc | HouseAge | AveRooms | AveBedrms | Population | AveOccup | Latitude | Longitude | MedHouseVal | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 2.344709 | 0.982119 | 0.628544 | -0.153754 | -0.974405 | -0.049595 | 1.052523 | -1.327803 | 2.129580 |
| 1 | 2.332181 | -0.607004 | 0.327033 | -0.263329 | 0.861418 | -0.092510 | 1.043159 | -1.322812 | 1.314124 |
| 2 | 1.782656 | 1.856137 | 1.155592 | -0.049015 | -0.820757 | -0.025842 | 1.038478 | -1.332794 | 1.258663 |
| 3 | 0.932945 | 1.856137 | 0.156962 | -0.049832 | -0.766010 | -0.050328 | 1.038478 | -1.337785 | 1.165072 |
| 4 | -0.012881 | 1.856137 | 0.344702 | -0.032905 | -0.759828 | -0.085614 | 1.038478 | -1.337785 | 1.172871 |
Étape 3 : Réduction de Dimension et Visualisation¶
Dans la dernière phase de notre analyse, on a appliqué l'algorithme t-SNE (t-distributed Stochastic Neighbor Embedding) pour réduire la dimensionnalité de nos données et les visualiser en 2D et 3D. Cette étape était cruciale pour obtenir des informations plus approfondies sur le jeu de données.
3.1 Algorithme t-SNE :¶
L'algorithme t-SNE, ou t-distributed Stochastic Neighbor Embedding, est une technique de réduction de dimension. Il utilise une distribution spécifique appelée distribution de Student (t-distribution) pour transformer des données de haute dimension en un espace de dimension inférieure. L'objectif est de préserver les relations entre les points. Pour ce faire, il groupe les points similaires et les éloigne les uns des autres dans l'espace de dimension réduite. La distribution de Student est essentielle car elle permet de former des groupes compacts de points similaires tout en maintenant une séparation adéquate entre les groupes distincts. Cela en fait un outil précieux pour la visualisation de données complexes et la découverte de structures cachées.
et voici une visualisation des résultats en 2D :
import pandas as pd
import plotly.express as px
from sklearn.manifold import TSNE
tsne = TSNE(n_components=2,
perplexity=50,
early_exaggeration=20.0,
init='pca',
random_state=10,
verbose=0)
df["quantile"] = pd.qcut(data["MedHouseVal"],
[0, .25, .5, .75, .9, 1.],
labels=False)
df_tsne = tsne.fit_transform(df.drop(["MedHouseVal"], axis=1))
df_tsne = pd.DataFrame(data={"col0": df_tsne[:, 0],
"col1": df_tsne[:, 1]})
df_tsne["value"] = data["MedHouseVal"]
df_tsne["income"] = data["MedInc"]
df_tsne["quantile"] = df["quantile"]
sample_tsne = df_tsne.sample(frac=0.9)
sample_tsne['quantile'] = sample_tsne['quantile'].astype(str)
fig = px.scatter(sample_tsne, x="col0", y="col1", size="income", color="quantile", text=None)
fig.update_layout(width=800, height=600,title="t-SNE 2D Visualization" ,title_x=0.5)
image_bytes = fig.to_image(format='png', width=1200, height=700, scale=1)
Image(image_bytes)
On peut voir, grâce à la couleur des bulles attribuée par la catégorie forcée, que l'algorithme parvient en quelque sorte à identifier des couches de prix en utilisant uniquement deux variables. Cependant, il est visible qu'il a encore du mal à former des groupes parfaitement distincts pour la valeur des catégories choisies.
3.2 Visualisation en 3D :¶
Nous avons étendu notre analyse en créant une visualisation en 3D pour obtenir une perspective plus complète sur le jeu de données. Voici un exemple du jeu de données sur les prix immobiliers de Californie dans l'espace tridimensionnel.
tsne3 = TSNE(n_components=3,
perplexity=30,
early_exaggeration=20.0,
init='pca',
random_state=10)
df_tsne3 = tsne3.fit_transform(df.drop(["MedHouseVal"], axis=1))
df_tsne3 = pd.DataFrame(data={"col0": df_tsne3[:,0],
"col1": df_tsne3[:,1],
"col2": df_tsne3[:,2]})
df_tsne3["value"] = data["MedHouseVal"]
df_tsne3["income"] = data["MedInc"]
df_tsne3["quantile"] = df["quantile"]
df_tsne3["quantile"] = df_tsne3["quantile"].astype(str)
sample_tsne3 = df_tsne3.sample(frac=1)
fig = px.scatter_3d(sample_tsne3,
x="col0", y="col1", z="col2",
color="quantile",
text=None)
fig.update_layout(width=800, height=600,title="t-SNE 3D Visualization" ,title_x=0.5)
image_bytes = fig.to_image(format='png', width=1200, height=700, scale=1)
from IPython.display import Image
Image(image_bytes)
3.4 PCA¶
from sklearn.decomposition import PCA
pca = PCA()
pca.fit(df.drop(["MedHouseVal","quantile"],axis=1))
# Explained variance ratio
explained_variance_ratio = pca.explained_variance_ratio_
# Cumulative explained variance
cumulative_variance = np.cumsum(explained_variance_ratio)
# Plot explained variance ratio
plt.figure(figsize=(10, 6))
plt.bar(range(1, len(explained_variance_ratio) + 1), explained_variance_ratio, alpha=0.7, align='center')
plt.xlabel('Principal Component')
plt.ylabel('Explained Variance Ratio')
plt.title('Explained Variance Ratio for Principal Components')
plt.show()
# Plot cumulative explained variance
plt.figure(figsize=(10, 6))
plt.plot(range(1, len(cumulative_variance) + 1), cumulative_variance, marker='o')
plt.xlabel('Number of Principal Components')
plt.ylabel('Cumulative Explained Variance')
plt.title('Cumulative Explained Variance for Principal Components')
plt.grid(True)
plt.show()
Conclusion :¶
En conclusion, cette méthodologie nous a permis d'obtenir des informations précieuses sur le jeu de données sur les prix immobiliers de Californie. En commençant par l'analyse des variables simples, on a compris les caractéristiques de base du jeu de données. L'analyse multivariée nous a aidés à découvrir les relations entre les variables, et la réduction de dimension par l'algorithme t-SNE nous a donné une compréhension plus approfondie de sa structure sous-jacente.